/*
  TypeScript不是一门新的语言，就是一个强类型版的js
  ts可以在编写时报错
  ts有了类型推断，增强了代码的健壮性，不容易出错了
  ts更适合大型项目的开发

  如果没有在脚手架里面，需要自己手动编译成js

  1. 全局安装ts
    cnpm i typescript -g

  2. 编译
    tsc ./src/index.ts --outFile ./dist/index.js

  3. 初始化ts的配置文件
    tsc --init

  4. 实时编译
    tsc --watch
*/

// 定义字符串类型
// 定义完了以后就没有办法变成其他类型的数据了
let str1: string = "hello";
let str2: string;
str2 = "world";
// ts会自动类型推断
let str3 = "hi";

// 定义数字类型
let num1: number = 10;
num1 = 20;

// 定义布尔值
let done1: boolean = true;
done1 = false;

// 定义undefined
// undefined类型只有一个值就是undefined
let udf1: undefined = undefined;

// 定义null
let nl1: null = null;

// const fn = (size: "large" | "middle" | "small") => {

// }
let str4: "hello" = "hello";

// const ids: string | null = localStorage.getItem("ids");
// if (ids) {
//   const arr = JSON.parse(ids);
// }

// 联合类型
// 用一个竖线表示或
let a: number | string | boolean = 5;
a = "5";
a = true;

// any表示任意类型
let b: any = {
  x: 3,
};

// 数组类型
let arr1: number[] = [1, 2, 3, 4, 5];
let arr2: Array<string> = ["a", "b", "c"];
let arr3: (number | string)[] = [1, 2, "3"];
let arr4: Array<string | number> = [1, 2, "3"];

// 元组类型(数组类型的补充)
// 可以规定数组的长度，以及数组里面每一项的数据类型
let arr5: [number, boolean] = [1, true];
// arr5.length = 5;

// 对象类型
// 对象类型需要使用interface接口方式进行定义
interface ObjType {
  name: string;
  age: number;
  // 问号表示可选属性
  sex?: number;
  // 索引签名
  // 其他属性不在乎的时候
  [propName: string]: any;
}
let obj1: ObjType = {
  name: "zhangsan",
  age: 20,
};
obj1.sex = 1;
// obj1.asgergtrt = () => {};

interface Obj2Type {
  x: number;
  y: number[];
}
const obj2: Obj2Type = {
  x: 10,
  y: [1, 2, 3],
};

interface Obj3ItemType {
  id: number;
  name: string;
}
const obj3: Obj3ItemType[] = [
  {
    id: 1,
    name: "zhangsan",
  },
  {
    id: 2,
    name: "lisi",
  },
];

interface LikeType {
  x: number;
  y: number;
}
interface Obj4Type {
  name: string;
  age: number;
  likes: LikeType;
}
const obj4 = {
  name: "zhansgsan",
  age: 20,
  likes: {
    x: 10,
    y: 20,
  },
};

interface Obj5Type {
  id: number;
  name: string;
  children?: Obj5Type[];
}
const obj5: Obj5Type[] = [
  {
    id: 1,
    name: "zhangsan",
    children: [
      {
        id: 11,
        name: "wangsan",
      },
      {
        id: 12,
        name: "lisan",
      },
    ],
  },
  {
    id: 2,
    name: "lisi",
  },
];

// 枚举类型(对象的扩展)
// 不仅可以用key找value，也可以用value找key
enum Color {
  Red = 10,
  Green = 15,
  Blue,
}
let gn: Color = Color.Green;
console.log(gn);
let bl: string = Color[16];
console.log(bl);

// 函数类型
// 函数只需要写函数的返回值类型
function fn1(): number {
  return 10;
}

// 函数的参数是不能自动推断，需要自己写
function fn2(x: number, y: string): string {
  return x + y;
}
fn2(3, "5");

// 参数加问号，表示是一个可选参数
function fn3(x: number, y?: number): number {
  return 100;
}
fn3(3, 4);
fn3(3);

const fn4: (x: number, y: number) => number = (
  x: number,
  y: number
): number => {
  return x + y;
};
fn4(3, 4);

// 当函数没有返回值的时候，写void
const fn5 = (): void => {
  console.log(123);
};
fn5();

// never表示从不
// 可以用在死循环或者报错的时候
const fn6 = (): never => {
  while (true) {}
};
const fn7 = (): never => {
  throw new Error("xxx错误");
};

// 泛型的定义(函数的扩展)
const fn8 = <T>(x: T, y: T) => {
  return 999;
};
fn8<number>(3, 4);
fn8<string>("3", "4");

// const count = ref<number>(10);
// const ref = <T>():  => {
//   // xxxx
//   return {
//     // xxx
//     // xxx
//     value: 10
//   }
// }
